package com.hsogoo.ultraman.spring;

import com.google.common.base.Splitter;
import com.google.common.collect.Maps;
import com.hsogoo.ultraman.Config;
import com.hsogoo.ultraman.ConfigService;
import com.hsogoo.ultraman.constants.PropertySourceConstants;
import com.hsogoo.ultraman.container.ConfigContainer;
import com.hsogoo.ultraman.listener.AutoRefreshConfigChangeListener;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.context.EnvironmentAware;
import org.springframework.core.Ordered;
import org.springframework.core.PriorityOrdered;
import org.springframework.core.env.CompositePropertySource;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.Environment;
import org.springframework.core.env.MapPropertySource;

import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicBoolean;

import lombok.extern.slf4j.Slf4j;

/**
 * Created by za-huangsaigang on 2018/9/17.
 */
@Slf4j
public class ConfigPropertySourceProcessor implements EnvironmentAware, BeanFactoryPostProcessor, PriorityOrdered {

    private ConfigurableEnvironment environment;
    private static final Splitter NAMESPACE_SPLITTER = Splitter.on(",").omitEmptyStrings().trimResults();
    private final ConfigPropertySourceFactory configPropertySourceFactory = ConfigContainer.getBean(ConfigPropertySourceFactory.class);
    private static final AtomicBoolean INITIALIZED = new AtomicBoolean(false);

    @Override
    public void setEnvironment(Environment environment) {
        this.environment = (ConfigurableEnvironment) environment;
    }

    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        log.info("ConfigPropertySourceProcessor.postProcessBeanFactory() invoked...");
        if (INITIALIZED.compareAndSet(false, true)) {
            initializePropertySources();
            initializeAutoUpdatePropertiesFeature(beanFactory);
        }
    }

    private void initializePropertySources(){
        if (environment.getPropertySources().contains(PropertySourceConstants.ULTRAMAN_CONFIG_BOOTSTRAP_NAME)) {
            //already initialized
            return;
        }
        List<String> namespaces = NAMESPACE_SPLITTER.splitToList(PropertySourceConstants.ULTRAMAN_DEFAULT_NAMESPACES);

        CompositePropertySource composite = new CompositePropertySource(PropertySourceConstants.ULTRAMAN_CONFIG_BOOTSTRAP_NAME);
        for (String namespace : namespaces) {
            Config config = ConfigService.getConfig(namespace);
            composite.addPropertySource(configPropertySourceFactory.getConfigPropertySource(namespace, config));
        }
        environment.getPropertySources().addFirst(composite);
    }

    private void initializeAutoUpdatePropertiesFeature(ConfigurableListableBeanFactory beanFactory) {

        AutoRefreshConfigChangeListener refreshConfigChangeListener = new AutoRefreshConfigChangeListener(
                environment, beanFactory);
        List<ConfigPropertySource> configPropertySources = configPropertySourceFactory.getAllConfigPropertySources();
        for (ConfigPropertySource configPropertySource : configPropertySources) {
            configPropertySource.addChangeListener(refreshConfigChangeListener);
        }
    }

    @Override
    public int getOrder() {
        return Ordered.HIGHEST_PRECEDENCE;
    }
}
